package ldap;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.logging.log4j.Logger;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

/**
 * @ClassName ldapLink2
 * @Description TODO
 * @Author dzf
 * @Date 2023/1/12 10:02
 * @Version 1.0
 */
public class ldapLink2 {

    Logger log ;

    //389登录
    // 只要不抛出异常就是验证通过
    public LdapContext adLogin(JSONObject json) {
        String username = json.getString("username");
        String password = json.getString("password");
        String server = "ldap://XXXXXXX.com:389";
        try {
            Hashtable<String, String> env = new Hashtable<String, String>();
            //用户名称，cn,ou,dc 分别：用户，组，域
            env.put(Context.SECURITY_PRINCIPAL, username);
            //用户密码 cn 的密码
            env.put(Context.SECURITY_CREDENTIALS, password);
            //url 格式：协议://ip:端口/组,域   ,直接连接到域或者组上面
            env.put(Context.PROVIDER_URL, server);
            //LDAP 工厂
            env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
            //验证的类型     "none", "simple", "strong"
            env.put(Context.SECURITY_AUTHENTICATION, "simple");
            LdapContext ldapContext = new InitialLdapContext(env, null);
            log.info("ldapContext:" + ldapContext);
            log.info("用户" + username + "登录验证成功");
            return ldapContext;

        } catch (NamingException e) {
            log.info("用户" + username + "登录验证失败");
            log.info("错误信息："+e.getExplanation());
            return null;
        }
    }

    //636登录
    //证书提前倒入的Java库中

    LdapContext adLoginSSL(JSONObject json) {
        String username = json.getString("username");
        String password = json.getString("password");
        Hashtable env = new Hashtable();

        String javaHome = System.getProperty("java.home");
        String keystore = javaHome+"/lib/security/cacerts";
        log.info("java.home,{}",keystore);
        // 加载导入jdk的域证书
        System.setProperty("javax.net.ssl.trustStore", keystore);
        System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
        String LDAP_URL = "ldaps://XXXXXX.com:636"; // LDAP访问地址

        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.SECURITY_PROTOCOL, "ssl");//链接认证服务器
        env.put(Context.PROVIDER_URL, LDAP_URL);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, username);
        env.put(Context.SECURITY_CREDENTIALS, password);
        try {
            LdapContext ldapContext = new InitialLdapContext(env, null);
            log.info("认证成功");// 这里可以改成异常抛出。
            return ldapContext;
        } catch (javax.naming.AuthenticationException e) {
            log.info("认证失败:{}",e.getMessage());
        } catch (Exception e) {
            log.info("认证出错：{}",e.getMessage());
        }
        return null;
    }

    //查询域用户信息
    public List getUserKey(JSONObject json){

        JSONObject admin = new JSONObject();
        admin.put("username","Aaaaa");
        admin.put("password", "bbbbbbbb");
        String name = json.getString("name");
        log.info("需要查询的ad信息：{}",name);
        List<JSONObject> resultList = new JSONArray();
        LdapContext ldapContext = adLogin(admin); //连接到域控
        if (ldapContext!=null){

            String company = "";
            String result = "";
            try {
                // 域节点
                String searchBase = "DC=XXXXXXX,DC=com";
                // LDAP搜索过滤器类
                //cn=*name*模糊查询
                // cn=name 精确查询
                // String searchFilter = "(objectClass="+type+")";
                String searchFilter = "(sAMAccountName="+name+")";    //查询域帐号

                // 创建搜索控制器
                SearchControls searchCtls = new SearchControls();
                String  returnedAtts[]={"description","sAMAccountName","userAccountControl"};
                searchCtls.setReturningAttributes(returnedAtts); //设置指定返回的字段，不设置则返回全部
                //  设置搜索范围 深度
                searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
                // 根据设置的域节点、过滤器类和搜索控制器搜索LDAP得到结果
                NamingEnumeration answer = ldapContext.search(searchBase, searchFilter,searchCtls);
                // 初始化搜索结果数为0
                int totalResults = 0;
                int rows = 0;
                while (answer.hasMoreElements()) {// 遍历结果集
                    SearchResult sr = (SearchResult) answer.next();// 得到符合搜索条件的DN
                    ++rows;
                    String dn = sr.getName();
                    log.info(dn);
                    Attributes Attrs = sr.getAttributes();// 得到符合条件的属性集
                    if (Attrs != null) {
                        try {
                            for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore();) {
                                Attribute Attr = (Attribute) ne.next();// 得到下一个属性
                                // 读取属性值
                                for (NamingEnumeration e = Attr.getAll(); e.hasMore(); totalResults++) {
                                    company = e.next().toString();
                                    JSONObject tempJson = new JSONObject();

                                    tempJson.put(Attr.getID(), company.toString());
                                    resultList.add(tempJson);
                                }
                            }
                        } catch (NamingException e) {
                            log.info("Throw Exception : " + e.getMessage());
                        }
                    }
                }
                log.info("总共用户数：" + rows);
            } catch (NamingException e) {
                log.info("Throw Exception : " + e.getMessage());
            }finally {
                try{
                    ldapContext.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        return resultList;
    }

    //重置用户密码
    // 管理员重置用户密码，后强制用户首次登录修改密码
    public Map<String, String> updateAdPwd(JSONObject json) {
        String dn = json.getString("dn");//要修改的帐号（这个dn是查询的用户信息里的dn的值，而不是域账号）
        String password = json.getString("password");//新密码

        JSONObject admin = new JSONObject();
        admin.put("username","aaaaaaa");
        admin.put("password", "bbbbbbb");
        Map<String,String> map = new HashMap<>();
        LdapContext ldapContext = adLoginSSL(admin); //连接636端口域
        ModificationItem[] mods = new ModificationItem[2];
        if (ldapContext!=null){
            try {
                String newQuotedPassword = "\"" + password + "\"";
                byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
                // unicodePwd：修改的字段，newUnicodePassword：修改的值
                mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
                        new BasicAttribute("unicodePwd", newUnicodePassword));
                mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
                        new BasicAttribute("pwdLastSet", "0"));  // 首次登录必须修改密码

                // 修改密码
                ldapContext.modifyAttributes(dn, mods);
                map.put("result", "S");
                map.put("message","成功");
            }catch (Exception e){
                map.put("result","E");
                map.put("message", "无法重置密码");
            }finally {
                try{
                    ldapContext.close();
                }catch (Exception e){
                    e.printStackTrace();
                }

            }

        }else {
            log.info("");
            map.put("result","E");
            map.put("message", "验证失败");
        }

        return map;
    }

    //域账号解锁
    // 表示锁定的字段需要测试，不一定这个lockoutTime
    public Map<String, String> deblocking(JSONObject json) {
        JSONObject admin = new JSONObject();
        String dn = json.getString("dn"); //被解锁的帐号（这个dn指的是查询用户信息里的dn的值，不是域账号）
        admin.put("username","aaaaaa");
        admin.put("password","bbbbbb");
        Map<String,String> map = new HashMap<String,String>();
        LdapContext ldapContext = adLogin(admin);
        ModificationItem[] mods = new ModificationItem[1];
        if (ldapContext!=null){
            try {
            // "0" 表示未锁定，不为0表示锁定
                mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
                        new BasicAttribute("lockoutTime","0"));
                // 解锁域帐号
                ldapContext.modifyAttributes(dn, mods);
                map.put("result", "S");
                map.put("message","成功");
            }catch (Exception e){
                map.put("result","E");
                map.put("message", "解锁失败");
            }finally {
                try{
                    ldapContext.close();
                }catch (Exception e){
                    e.printStackTrace();
                }

            }

        }else {
            map.put("result","E");
            map.put("message", "验证失败");
        }
        return map;
    }

    public static void main(String[] args) {

    }
}
